home *** CD-ROM | disk | FTP | other *** search
/ Programmer Plus 2007 / Programmer-Plus-2007.iso / Programming / Low Level Languages / PCLOGO / LOGO / SHED.LG_ / SHED.LG
Encoding:
Text File  |  1994-05-23  |  11.6 KB  |  460 lines

  1. ; Turtle Shape Editor (C) 1994 by Harvard Associates, Inc.
  2.  
  3. IGNORE IF NOT DEFINED? "BEEP [LOAD "WINDOWS]
  4.  
  5. NOCASE
  6.  
  7. TO SHED
  8.     SHAPE.EDITOR
  9. END
  10.  
  11. TO SHAPE.EDITOR
  12.     ; start with the shape of the current turtle
  13.     LOCAL "LIST
  14.     MAKE "LIST (LIST (SHAPE 1) (SHAPE 2) (SHAPE 3) (SHAPE 4))
  15.     DRAW SS
  16.     (SETSHAPE ITEM 1 :LIST ITEM 2 :LIST ITEM 3 :LIST ITEM 4 :LIST)
  17.     SETUP.WINDOW
  18.     GET.SHAPE
  19.     DRAW.WINDOW
  20.     PROCESS.MOUSE
  21.     DRAW
  22.     TELLALL 1 4 (SETSHAPE) HT
  23.     SETEXTENT 0
  24.     TELL 0 ST
  25.     (SETSHAPE ITEM 1 :LIST ITEM 2 :LIST ITEM 3 :LIST ITEM 4 :LIST)
  26.     (SETMOUSESHAPE)
  27. END
  28.  
  29. ; define various constant values and set up the coordinate system
  30.  
  31. TO SETUP.WINDOW
  32.     LOCAL "I
  33.     MAKE "DOT.SIZE 15                ; size of a drawn dot
  34.     MAKE "WIDTH 16 * :DOT.SIZE + 200 ; define window width and height
  35.     MAKE "HEIGHT 16 * :DOT.SIZE + 16
  36.     MAKE "X.OFFSET (-:WIDTH / 2)
  37.     MAKE "Y.OFFSET -8 * :DOT.SIZE + :DOT.SIZE + 8
  38.     MAKE "TEXT.POS LIST (:X.OFFSET + 2) (:HEIGHT / 2 + 1)
  39.     ; the lower left corners of the four shapes
  40.     MAKE "SHAPE.POS (ARRAY 4 [[50 60][90 60][130 60][170 60]])
  41.     ; the lower left corners of the buttons
  42.     MAKE "BUTTON.POS (ARRAY 5 [ \
  43.         [Load 80 15] \
  44.         [Save 80 -15] \
  45.         [Restore 80 -45] \
  46.         [Clear 80 -75] \
  47.         [Done 80 -115]])
  48.     SETWINSIZE :WIDTH + 2 :HEIGHT + 2
  49.     (SETEXTENT :WIDTH/2 + 1 :HEIGHT/2 + 2); tie extent to window
  50.     MAKE "SHAPE BYTEARRAY [4 32]  ; storage for the turtle shape
  51.     MAKE "ORIG.SHAPE BYTEARRAY [4 32]; original shape for restore
  52.     ; shape changed flags
  53.     FOR "I 1 4 [MAKE WORD "CHANGED. :I "FALSE]
  54.     MAKE "CUR.SHAPE 1             ; shape 1 is the current shape (n - 1)
  55.     MAKE "CUR.TEXT.NR 0           ; current help text number
  56. END
  57.  
  58. ; draw the initial window look
  59.  
  60. TO DRAW.WINDOW
  61.     LOCAL "I
  62.     DRAW
  63.     SET.TITLE [Turtle Shape Editor]
  64.     ; draw the bottom line
  65.     HT SETPC 0
  66.     PU SETXY LIST (-:WIDTH/2) (:HEIGHT / 2 - 16)
  67.     PD SETXY LIST ( :WIDTH/2) (:HEIGHT / 2 - 16)
  68.     DRAW.GRID
  69.     ; draw the four boxes
  70.     SETPC 0
  71.     FOR "I 1 4 [DRAW.BOX :I]
  72.     FOR "I 1 4 [SETUP.TURTLE :I]
  73.     FOR "I 1 5 [DRAW.BUTTON :I]
  74.     DRAW.DOTS
  75.     TELL 0
  76. END
  77.  
  78. ; setup a demo turtle
  79.  
  80. TO SETUP.TURTLE :NR
  81.     (LOCAL "X "Y "POS)
  82.     MAKE "POS AGET :SHAPE.POS :NR - 1
  83.     MAKE "X (FIRST :POS) + 14
  84.     MAKE "Y (LAST :POS)  + 14
  85.     TELL :NR
  86.     SETPC 4 
  87.     PU SETXY LIST :X :Y 
  88.     PD SETH 22.5 * (:NR - 1) ST
  89.     TELL 0
  90. END
  91.  
  92. TO DRAW.BUTTON :NR
  93.     (LOCAL "POS "SIZE "X "Y)
  94.     MAKE "POS AGET :BUTTON.POS :NR - 1
  95.     PU SETXY BF :POS
  96.     PD SETPC 7          ; light gray interior
  97.     (STAMPRECT 90 25 "TRUE)
  98.     ; draw the gray and white interior frame
  99.     MAKE "X ITEM 2 :POS
  100.     MAKE "Y ITEM 3 :POS
  101.     PU SETXY LIST :X + 2 :Y + 1
  102.     SETWIDTH 2
  103.     SETPC 15
  104.     PD FD 21 RT 90 FD 86
  105.     SETPC 8
  106.     RT 90 FD 21 RT 90 FD 86
  107.     SETWIDTH 1 SETHEADING 0
  108.     SETPEN [PU 0] SETXY BF :POS
  109.     PD STAMPRECT 90 25     ; black border
  110.     MAKE "SIZE TEXTSIZE :.GRAPHICS FIRST :POS
  111.     PU 
  112.           SETY YCOR + (25 - (LAST :SIZE)) / 2 + LAST :SIZE
  113.     SETX XCOR + (90 - (FIRST :SIZE)) / 2
  114.     PD TURTLETEXT FIRST :POS
  115. END
  116.  
  117. ; draw the shape grid with the current shape
  118.  
  119. TO DRAW.GRID
  120.     (LOCAL "X "Y)
  121.     PU
  122.       SETXY COMPUTE.COORDS 0 15
  123.     SETPC 15 PD
  124.     ; erase the grid
  125.     (STAMPRECT 16 * :DOT.SIZE 16 * :DOT.SIZE "TRUE)
  126.     SETPC 0
  127.     FOR "X 0 16 [DRAW.VLINE :X]
  128.     FOR "Y 0 15 [DRAW.HLINE :Y] 
  129.     MAKE "OLD.POS [-1 -1]         ; old mouse posiiton in bit array
  130.     MAKE "OLD.VAL 0               ; old dot value in mouse array
  131. END
  132.  
  133. ; draw the dots within the shape grid
  134.  
  135. TO DRAW.DOTS
  136.     (LOCAL "X "Y "OLD)
  137.     MAKE "OLD MOUSESHAPE
  138.     SETMOUSESHAPE 3
  139.     FOR "X 0 15 [ \
  140.         FOR "Y 0 15 [(DRAW.DOT :X :Y TEST.BIT :X :Y "FALSE)]]
  141.     SETMOUSESHAPE :OLD
  142. END
  143.  
  144. TO DRAW.HLINE :Y
  145.     PU
  146.       SETXY LIST :X.OFFSET (- :Y * :DOT.SIZE + :Y.OFFSET)
  147.     PD SETX 16 * :DOT.SIZE + :X.OFFSET - 1
  148. END
  149.  
  150. TO DRAW.VLINE :X
  151.     PU
  152.       SETXY LIST (:X * :DOT.SIZE + :X.OFFSET - 1) (- :Y.OFFSET - :DOT.SIZE)
  153.     PD SETY :Y.OFFSET - 2 * :DOT.SIZE - 1
  154. END
  155.  
  156. ; Draw a box around a mouse shape. Draw a thick
  157. ; box for the current shape.
  158.  
  159. TO DRAW.BOX :SHAPE.NR
  160.     PU SETXY AGET :SHAPE.POS :SHAPE.NR - 1
  161.     PD SETPC 15
  162.     ; erase any old box
  163.     SETWIDTH 3 STAMPRECT 30 30
  164.     IF NOT :SHAPE.NR = :CUR.SHAPE [SETWIDTH 1]
  165.     SETPC 0 STAMPRECT 30 30
  166.     SETWIDTH 1
  167. END
  168.  
  169. ; draw a dot at a certain location
  170. ; X and Y vary between 0 and 15
  171.  
  172. TO DRAW.DOT :X :Y :ON [:FORCE "TRUE] 3
  173.     IF AND NOT :ON NOT :FORCE THEN STOP     ; do not draw white if no force
  174.     TEST :ON
  175.     IFTRUE [SETPC 12]                       ; red for on-dots
  176.     IFFALSE [SETPC 15]                      ; white for off-dots
  177.     MAKE "X COMPUTE.COORDS :X :Y
  178.     PU SETXY :X PD
  179.     (STAMPRECT :DOT.SIZE :DOT.SIZE "TRUE)   ; draw filled rect
  180. END
  181.  
  182. ; compute the lower left corner for a given coordinate
  183. ; RETURN IT AS A TWO-ELEMENT LIST FOR X and Y
  184.  
  185. TO COMPUTE.COORDS :X :Y
  186.     MAKE "X :X * :DOT.SIZE + :X.OFFSET      ; starting pos of rect
  187.     MAKE "Y (- :Y * :DOT.SIZE + :Y.OFFSET)
  188.     OUTPUT LIST :X :Y
  189. END
  190.  
  191. ; convert the current shape into a BYTEARRAY 32x4
  192. ; and store it into SHAPE
  193.  
  194. TO GET.SHAPE
  195.     FILLARRAY :SHAPE (LIST (SHAPE 1) (SHAPE 2) (SHAPE 3) (SHAPE 4))
  196.     FILLARRAY :ORIG.SHAPE (LIST (SHAPE 1) (SHAPE 2) (SHAPE 3) (SHAPE 4))
  197. END
  198.  
  199. ; convert the bytearray SHAPE into a shape list and set the shape
  200.  
  201. TO SET.SHAPE
  202.     LOCAL "LIST
  203.     MAKE "LIST LISTARRAY :SHAPE
  204.     (SETSHAPE ITEM 1 :LIST ITEM 2 :LIST ITEM 3 :LIST ITEM 4 :LIST)
  205. END
  206.  
  207. ; compute the position of any given bit in the current shape
  208. ; the index into the BYTEARRAY is stored in BYTE, 
  209. ; and the bit mask which is used to AND or OR the bit into
  210. ; the byte number is stored in BIT
  211. ; every two elements in the shape list are one row of dots
  212. ; if X is >= 8, then the second element is used
  213.  
  214. TO COMPUTE.BIT.POSITION :X :Y
  215.     MAKE "BYTE :Y * 2
  216.     MAKE "BIT :X
  217.     IF :X >= 8 THEN MAKE "BYTE :BYTE + 1 MAKE "BIT :X - 8
  218.     MAKE "BIT LSH #h80 :BIT
  219.     MAKE "BYTE LIST (:CUR.SHAPE - 1) :BYTE
  220. END
  221.  
  222. ; test a bit for being set in the current shape
  223. ; returns TRUE or FALSE
  224.  
  225. TO TEST.BIT :X :Y
  226.     COMPUTE.BIT.POSITION :X :Y
  227.     OUTPUT NOT (LOGAND AGET :SHAPE :BYTE :BIT) = 0
  228. END
  229.  
  230. ; set or reset a bit in the current shape
  231.  
  232. TO SET.BIT :X :Y :ON
  233.     COMPUTE.BIT.POSITION :X :Y
  234.     IF :ON ASET :SHAPE :BYTE LOGOR AGET :SHAPE :BYTE :BIT \
  235.         ELSE ASET :SHAPE :BYTE LOGAND AGET :SHAPE :BYTE LOGNOT :BIT
  236.     MAKE WORD "CHANGED. :CUR.SHAPE "TRUE
  237.     TELL :CUR.SHAPE
  238.     SET.SHAPE
  239.     TELL 0
  240. END
  241.  
  242. ; perform a hit test for the given turtle coordinates.
  243. ; If a box if hit, return 1 to 4 according to the shape.
  244. ; If a dot square is hit, return a list of X and Y
  245. ; coordinates ranging from 0 to 15 each. If a button is hit,
  246. ; negative values from -1 to -4 are outputted
  247.  
  248. TO HIT.TEST :COORDS
  249.     (LOCAL "X "Y "I)
  250.     MAKE "X FIRST :COORDS
  251.     MAKE "Y LAST :COORDS
  252.     IF :X < (:X.OFFSET + 16 * :DOT.SIZE) [OUTPUT OVER.DOT? :X :Y]
  253.     FOR "I 1 4 [IF OVER.BOX? :I :X :Y [OUTPUT :I]]
  254.     FOR "I 1 5 [IF OVER.BUTTON? :I :X :Y [OUTPUT (- :I)]]
  255.     OUTPUT []
  256. END
  257.  
  258. ; check if the given coordinates X and Y are over a dot box
  259. ; and output a two-element list of the bit positions of that dot
  260. ; if so. Output an empty list if not.
  261. ; dot box X and Y, where X and Y are the bit positions 0-15
  262. ; output TRUE or FALSE
  263.  
  264. TO OVER.DOT? :X :Y
  265.     MAKE "X   INT (:X - :X.OFFSET) / :DOT.SIZE
  266.     MAKE "Y (- INT (:Y - :HEIGHT/2 + 16) / :DOT.SIZE)
  267.     IF AND :X < 16 :Y < 16 [OUTPUT LIST :X :Y]
  268.     OUTPUT []
  269. END
  270.  
  271. TO OVER.BOX? :NR :X :Y
  272.     (LOCAL "X1 "Y1 "X2 "Y2)
  273.     MAKE "X2 AGET :SHAPE.POS :NR - 1
  274.     MAKE "X1 FIRST :X2
  275.     MAKE "Y1 LAST :X2
  276.     MAKE "X2 :X1 + 29
  277.     MAKE "Y2 :Y1 + 29
  278.     OUTPUT (AND :X >= :X1 :X <= :X2 :Y >= :Y1 :Y <= :Y2)
  279. END
  280.  
  281. TO OVER.BUTTON? :NR :X :Y
  282.     (LOCAL "X1 "Y1 "X2 "Y2)
  283.     MAKE "X2 BF AGET :BUTTON.POS :NR - 1
  284.     MAKE "X1 FIRST :X2
  285.     MAKE "Y1 LAST :X2
  286.     MAKE "X2 :X1 + 89
  287.     MAKE "Y2 :Y1 + 24
  288.     OUTPUT (AND :X >= :X1 :X <= :X2 :Y >= :Y1 :Y <= :Y2)
  289. END
  290.  
  291. ; process mouse input
  292.  
  293. TO PROCESS.MOUSE
  294.     LOCAL "POS
  295.     MAKE "POS HIT.TEST MOUSE
  296.     ; change the mouse shape according to the position
  297.     IF EMPTY? :POS THEN SETMOUSESHAPE 1 HELP.TEXT 0 \
  298.         ELSE IF LIST? :POS THEN SETMOUSESHAPE 15 HELP.TEXT 1 \
  299.             ELSE IF :POS > 0 THEN SETMOUSESHAPE 17 HELP.TEXT 2 \
  300.                 ELSE SETMOUSESHAPE 1 HELP.TEXT :POS
  301.     ; process mouse clicks
  302.     IF BUTTON? 1 THEN IF PROCESS.CLICK1 :POS THEN STOP
  303.     IF BUTTON? 2 THEN PROCESS.CLICK2 :POS
  304.     PROCESS.MOUSE
  305. END
  306.  
  307. ; set a certain help text
  308.  
  309. TO HELP.TEXT :TEXT.NR
  310.     IF :TEXT.NR = :CUR.TEXT.NR THEN STOP
  311.     PU SETXY :TEXT.POS
  312.      ; erase any old text
  313.     SETH 0 PU BK 16 PD
  314.     SETPC 15 PD (STAMPRECT :WIDTH 18 "TRUE)
  315.     PU FD 16 PD SETPC 0
  316.     ; draw any new text
  317.     IF :TEXT.NR = 1 THEN TT [Click the left button to set, the right button to reset a dot]
  318.     IF :TEXT.NR = 2 THEN TT [Click to select a shape to edit]
  319.     ; draw text for buttons
  320.     IF :TEXT.NR = -1 THEN TT [Click to load a shape from disk]
  321.     IF :TEXT.NR = -2 THEN TT [Click to save a shape to disk]
  322.     IF :TEXT.NR = -3 THEN TT [Click to undo the changes]
  323.     IF :TEXT.NR = -4 THEN TT [Click to erase the shape]
  324.     IF :TEXT.NR = -5 THEN TT [Click if you have finished editing]
  325.     MAKE "CUR.TEXT.NR :TEXT.NR
  326. END
  327.  
  328. ; process a click on the left button
  329.  
  330. TO PROCESS.CLICK1 :POS
  331.     IF EMPTY? :POS THEN OP "FALSE
  332.     IF LIST? :POS THEN PROCESS.DOT FIRST :POS LAST :POS "TRUE OP "FALSE
  333.     IF :POS = -1 THEN PROCESS.LOAD OP "FALSE
  334.     IF :POS = -2 THEN PROCESS.SAVE OP "FALSE
  335.     IF :POS = -3 THEN PROCESS.DFLT OP "FALSE
  336.     IF :POS = -4 THEN PROCESS.ERASE OP "FALSE
  337.     IF :POS = -5 THEN PROCESS.DONE OP "TRUE
  338.     PROCESS.SHAPE :POS
  339.     OP "FALSE
  340. END
  341.  
  342. ; process a click on the right button
  343.  
  344. TO PROCESS.CLICK2 :POS
  345.     IF NOT LIST? :POS THEN STOP
  346.     PROCESS.DOT FIRST :POS LAST :POS "FALSE
  347. END
  348.  
  349. ; process a click in the dot area
  350.  
  351. TO PROCESS.DOT :X :Y :ON
  352.     LOCAL "VAL
  353.     MAKE "VAL LIST :X :Y
  354.     IF AND EQUAL? :OLD.VAL :ON EQUAL? :VAL :OLD.POS THEN STOP
  355.     MAKE "OLD.POS :VAL
  356.     MAKE "OLD.VAL :ON
  357.     SET.BIT :X :Y :ON
  358.     DRAW.DOT :X :Y :ON
  359.     TELL :CUR.SHAPE                         ; activate the current turtle
  360.     SET.SHAPE                               ; change the shape to show changes
  361.     TELL 0
  362. END
  363.  
  364. ; process a click in the shape area
  365.  
  366. TO PROCESS.SHAPE :NR
  367.     LOCAL "OLD.SHAPE
  368.     IF :NR = :CUR.SHAPE THEN STOP
  369.     MAKE "OLD.SHAPE :CUR.SHAPE
  370.     MAKE "CUR.SHAPE :NR
  371.     DRAW.BOX :OLD.SHAPE
  372.     DRAW.BOX :CUR.SHAPE
  373.     DRAW.GRID
  374.     DRAW.DOTS
  375. END
  376.  
  377. ; process the DFLT button
  378.  
  379. TO PROCESS.DFLT
  380.     LOCAL "I
  381.     IF NOT REPLY [Do you want to restore the original shape?] THEN STOP
  382.     MAKE "SHAPE :ORIG.SHAPE
  383.     TELLALL 1 4
  384.     SET.SHAPE
  385.     TELL 0
  386.     DRAW.GRID 
  387.     DRAW.DOTS
  388. END
  389.  
  390. ; process the LOAD button
  391.  
  392. TO PROCESS.LOAD
  393.     IF SHAPE.CHANGED? THEN \
  394.         IF REPLY [Do you want to save the shape?] THEN PROCESS.SAVE
  395.     TELLALL 1 4 (SETSHAPE)
  396.     MAKE "STANDARD.OUTPUT OPEN "NUL
  397.     IGNORE LOAD "|*.SHP|
  398.     CLOSE :STANDARD.OUTPUT
  399.     MAKE "STANDARD.OUTPUT 0
  400.     GET.SHAPE
  401.     ST TELL 0 HT
  402.     DRAW.GRID
  403.     DRAW.DOTS
  404. END
  405.  
  406. ; process the SAVE button
  407.  
  408. TO PROCESS.SAVE
  409.     (LOCAL "N "LIST "I)
  410.     IF NOT SHAPE.CHANGED? THEN STOP
  411.     MAKE "N CREATE "|*.SHP|
  412.     IF :N = -1 THEN STOP
  413.     MAKE "STANDARD.OUTPUT :N
  414.     MAKE "LIST LISTARRAY :SHAPE
  415.     (PR "\( "SETSHAPE "| \|)
  416.     FOR "I 1 4 [(PR "| [| ITEM :I :LIST "|] \|)]
  417.     PR "\)
  418.     CLOSE :N
  419.     MAKE "STANDARD.OUTPUT 0
  420.     FOR "I 1 4 [MAKE WORD "CHANGED. :I "FALSE]
  421. END
  422.  
  423. ; process the ERASE button
  424.  
  425. TO PROCESS.ERASE
  426.     IF THING WORD "CHANGED. :CUR.SHAPE \
  427.         IF NOT REPLY [Do you really want to clear this shape?"] STOP
  428.     FOR "I 0 31 [ASET :SHAPE LIST (:CUR.SHAPE - 1) :I 0]
  429.     TELL :CUR.SHAPE SET.SHAPE
  430.     TELL 0
  431.     DRAW.GRID
  432. END
  433.  
  434. ; process the DONE button
  435.  
  436. TO PROCESS.DONE
  437.     IF SHAPE.CHANGED? \
  438.         IF REPLY [Do you want to save the shape?] \
  439.             THEN PROCESS.SAVE
  440.     TELLALL 0 4 (SETSHAPE)
  441.     TELL 0
  442.     SET.TITLE [Graphics]
  443. END
  444.  
  445. ; check if any shape is altered
  446.  
  447. TO SHAPE.CHANGED?
  448.     LOCAL "I
  449.     FOR "I 1 4 [IF THING WORD "CHANGED. :I THEN OUTPUT "TRUE]
  450.     OUTPUT "FALSE
  451. END
  452.  
  453. ; print a nice message
  454.  
  455. CT
  456. PR [Turtle shape editor (C) 1994 by Harvard Associates, Inc.]
  457. PR [Enter SHED or SHAPE.EDITOR to start the program]
  458.  
  459. CASE
  460.